package net.ib.mtalk.ui.chat;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Date;
import java.util.UUID;

import net.ib.mntalk.protocol.Common;
import net.ib.mntalk.protocol.Common.Attachment;
import net.ib.mntalk.protocol.Common.BuddyInfo;
import net.ib.mntalk.protocol.Common.ControlMessage;
import net.ib.mntalk.protocol.Common.SystemMessage;
import net.ib.mntalk.protocol.Common.SystemMessageOption;
import net.ib.mntalk.protocol.Common.UUIDMsg;
import net.ib.mntalk.protocol.Common.UserMessage;
import net.ib.mntalk.protocol.Session.RemoveMessagesReq;
import net.ib.mntalk.protocol.Session.SendMessageReq;
import net.ib.mntalk.protocol.client.Database;
import net.ib.mntalk.protocol.client.Database.FileTransferInfo;
import net.ib.mtalk.R;
import net.ib.mtalk.constant.MTalkConstant;
import net.ib.mtalk.database.DatabaseContract.MessageTable;
import net.ib.mtalk.database.DatabaseContract.MessageTable.MessageStatus;
import net.ib.mtalk.database.helper.BuddyDatabaseHelper;
import net.ib.mtalk.database.helper.ChatDatabaseHelper;
import net.ib.mtalk.database.helper.InboxDatabaseHelper;
import net.ib.mtalk.global.GlobalPreferences;
import net.ib.mtalk.network.task.FileDownloadTask;
import net.ib.mtalk.network.task.FileUploadTask;
import net.ib.mtalk.network.task.RemoveMessagesTask;
import net.ib.mtalk.network.task.SendMessageTask;
import net.ib.mtalk.service.SelecterService;
import net.ib.mtalk.ui.attachment.emoticon.RichString;
import net.ib.mtalk.ui.attachment.geotag.GeotagActivity;
import net.ib.mtalk.ui.attachment.vcalendar.ReadVCalendarActivity;
import net.ib.mtalk.ui.attachment.vcard.VCardReadActivity;
import net.ib.mtalk.ui.buddy.item.BuddyActionItem;
import net.ib.mtalk.ui.buddy.item.BuddyActionItem.ItemType;
import net.ib.mtalk.ui.widget.QuickAction;
import net.ib.mtalk.util.Dip;
import net.ib.mtalk.util.GpbSupport;
import net.ib.mtalk.util.GraphicUtil;
import net.ib.mtalk.util.ImageManager;
import net.ib.mtalk.util.MTalkLogWriter;
import net.ib.mtalk.util.ProfileImageLoader;
import net.ib.mtalk.util.TimeAdapter;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.v4.widget.CursorAdapter;
import android.text.ClipboardManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

import com.google.protobuf.micro.InvalidProtocolBufferMicroException;

/**
 * 채팅창 어댑터!
 * TODO : 	
 * 			2. 섬네일 만들기
 * 			4. 리드마크 표시해주기! 
 * 
 * @author happy2v
 *
 */
public class ChatListCursorAdapter extends CursorAdapter {

	public static final int THUMB_LOAD_SIZE_DIP = 80;
	public static final int THUMB_MAX_SIZE_DIP = 120;

	protected Activity mActivity;
	protected Handler mHandler;

	private long mDateTime;

	private int mLayout;

	public ChatListCursorAdapter(Activity activity, Cursor c) {
		super(activity, c, true);
		initialize(activity);
	}

	public ChatListCursorAdapter(Activity activity, Cursor c, int flag) {
		super(activity, c, flag);
		initialize(activity);
	}

	private void initialize(Activity activity) {
		mActivity = activity;
		mHandler = new Handler();
		mDateTime = 0L;
		mLayout = R.layout.list_item_chat;
	}

	@Override
	public View newView(Context context, Cursor cursor, ViewGroup parent) {
		LayoutInflater inflater = LayoutInflater.from(context);
		View view = inflater.inflate(mLayout, parent, false);

		BalloonHolder holder = new BalloonHolder();
		holder.textDate = (TextView) view.findViewById(R.id.textDate);
		holder.textSystem = (TextView) view.findViewById(R.id.textSystem);

		holder.parentRcv = (RelativeLayout) view.findViewById(R.id.parentRcv);
		holder.imageProfile = (ImageView) view.findViewById(R.id.imageProfile);
		holder.textName = (TextView) view.findViewById(R.id.textName);
		holder.imageRcvContent = (ImageView) view.findViewById(R.id.imageRcvContent);
		holder.textRcvContent = (TextView) view.findViewById(R.id.textRcvContent);
		holder.textRcvTime = (TextView) view.findViewById(R.id.textRcvTime);
		holder.lLayoutRcvContent = (LinearLayout) view.findViewById(R.id.lLayoutRcvContent);

		holder.seekbarRcvProgress = (SeekBar) view.findViewById(R.id.seekbarRcvProgress);
		holder.seekbarRcvProgress.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			int originalProgress = 0;

			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
				// do nothing
			}

			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
				originalProgress = seekBar.getProgress();	// remember
			}

			@Override
			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
				if (fromUser == true) {
					seekBar.setProgress(originalProgress);	// role-back user input
				}
			}
		});
		holder.seekbarRcvProgress.setProgressDrawable(context.getResources().getDrawable(R.drawable.attachment_progressbar));

		holder.parentSnd = (RelativeLayout) view.findViewById(R.id.parentSnd);
		holder.textSndContent = (TextView) view.findViewById(R.id.textSndContent);
		holder.imageSndContent = (ImageView) view.findViewById(R.id.imageSndContent);
		holder.textSndTime = (TextView) view.findViewById(R.id.textSndTime);
		holder.chatSendStatus = (ImageView) view.findViewById(R.id.chat_send_status);
		holder.textUnreadCount = (TextView) view.findViewById(R.id.chat_send_count);
		holder.progressBalloon = (ProgressBar) view.findViewById(R.id.progressBalloon);
		holder.imageAlert = (ImageView) view.findViewById(R.id.imageAlert);
		holder.lLayoutSndContent = (LinearLayout) view.findViewById(R.id.lLayoutSndContent);

		holder.seekbarSndProgress = (SeekBar) view.findViewById(R.id.seekbarSndProgress);
		holder.seekbarSndProgress.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

			int originalProgress = 0;

			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
				// do nothing
			}

			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
				originalProgress = seekBar.getProgress();	// remember
			}

			@Override
			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
				if (fromUser == true) {
					seekBar.setProgress(originalProgress);	// role-back user input
				}
			}
		});
		holder.seekbarSndProgress.setProgressDrawable(context.getResources().getDrawable(R.drawable.attachment_progressbar));

		view.setTag(holder);
		return view;
	}

	private static class BalloonHolder {
		TextView textDate;
		TextView textSystem;
		ImageView imageProfile;
		TextView textName;
		ViewGroup parentRcv;
		ViewGroup parentSnd;

		TextView textRcvContent;
		ImageView imageRcvContent;
		TextView textRcvTime;
		LinearLayout lLayoutRcvContent;

		SeekBar seekbarRcvProgress;

		TextView textSndContent;
		ImageView imageSndContent;
		TextView textSndTime;

		ImageView chatSendStatus;
		TextView textUnreadCount;

		ProgressBar progressBalloon;
		ImageView imageAlert;
		LinearLayout lLayoutSndContent;

		SeekBar seekbarSndProgress;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		if (!mDataValid) {
			throw new IllegalStateException("this should only be called when the cursor is valid");
		}
		if (!mCursor.moveToPosition(position)) {
			throw new IllegalStateException("couldn't move cursor to position " + position);
		}

		View v;
		if (convertView == null) {
			v = newView(mContext, mCursor, parent);
			((ChatListActivity)mContext).mExistFlag = true;
		} else {
			v = convertView;
		}

		bindView(v, mContext, mCursor);

		return v;
	}

	@Override
	public void bindView(View view, Context context, Cursor cursor){
		/*
		 * 이 함수는 가능한한 빨리 끝나야 한다. 이미 얻어낸 데이터를 다시 얻는 경우를 피하자.
		 * */

		BalloonHolder holder = (BalloonHolder)view.getTag();
		final long msgTime = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_TIME));

		// 현재 메시지의 시간을 분석, 앞에 날짜 메시지를 넣어줘야 한다면 넣어주자.
		bindViewTime(cursor, holder, msgTime);

		// 메시지 타입에 따른 분기
		final int objType = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_OBJECT_TYPE));
		if (MessageTable.MessageObjectType.SYSTEM.getCode() == objType) {
			bindViewSystemMessage(cursor, holder);
			return;
		} else if(MessageTable.MessageObjectType.CONTROL.getCode() == objType) {
			bindViewControlMessage(cursor, holder);
			return;
		} else if (MessageTable.MessageObjectType.USER.getCode() == objType) {
			// continue without return.
		} else {
			MTalkLogWriter.e("ChatListCursorAdapter.bindView(): Should not reach here. message type unknown.");
			return;
		}
		// 이하는 유저 메시지에 대한 처리이다.

		// Thumbnail 이 있는지 확인한다. 있으면 선처리.
		final int thumbnailColumn = cursor.getColumnIndexOrThrow(MessageTable.KEY_THUMBNAIL);
		Bitmap thumbnailImg = bindViewThumbnail(cursor, holder, thumbnailColumn);

		// 보낸 메시지인지 받은 메시지인지 확인
		final int sendMessage = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_SEND_MESSAGE));
		if (MessageTable.SendMessage.YES.ordinal() == sendMessage) {	// 보낸 메시지일 때.
			holder.parentRcv.setVisibility(View.GONE);
			holder.textSystem.setVisibility(View.GONE);
			holder.parentSnd.setVisibility(View.VISIBLE);
			holder.seekbarSndProgress.setVisibility(View.GONE);

			// 전송 시간을 나타내어 준다.
			try {
				holder.textSndTime.setText(TimeAdapter.Date2Str(new Date(msgTime), "kk:mm"));
			} catch (NullPointerException e1) {
				MTalkLogWriter.e(e1);
				// 컴파일 시간에 해결해야 한다.
			} catch (IllegalArgumentException e2) {
				MTalkLogWriter.e(e2);
				// 시간 표시 안 하면 된다.
			}

			// 내용 세팅하기
			try {
				final int message = cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE);
				final UserMessage um = Common.UserMessage.parseFrom(cursor.getBlob(message));

				int contentType = um.getContentType();
				if (contentType == Common.CONTENT_TYPE_PLAIN) {
					bindViewSentText(cursor, holder, um);
				} else if (contentType == Common.CONTENT_TYPE_ATTACHMENT && um.hasAttachment()) { // 작은 용량의 파일일 때.
					holder.textSndContent.setVisibility(View.VISIBLE);
					holder.imageSndContent.setVisibility(View.VISIBLE);

					String mimeType = um.getAttachment().getMimeType();
					if (MTalkConstant.MIME_TYPE_VCARD.equals(mimeType)) {
						bindViewSentVcard(cursor, holder, um, thumbnailImg);
					} else if (MTalkConstant.MIME_TYPE_VCALENDAR.equals(mimeType)) {
						bindViewSentVcalendar(cursor, holder, um, thumbnailImg);
					} else if (MTalkConstant.MIME_TYPE_GEOTAG.equals(mimeType)) {
						bindViewSentGeotag(cursor, holder, um, thumbnailImg);
					} else {	// unknown Type
						holder.textSndContent.setVisibility(View.VISIBLE);
						holder.textSndContent.setText(R.string.attachment_unknown);
						holder.imageSndContent.setVisibility(View.GONE);
					}
				} else if (contentType == Common.CONTENT_TYPE_HTML && um.hasAttachFile()) {	// 동영상/이미지/목소리 등 파일일 때
					holder.seekbarSndProgress.setVisibility(View.GONE);
					holder.textSndContent.setVisibility(View.VISIBLE);
					holder.imageSndContent.setVisibility(View.VISIBLE);

					int fileType = um.getAttachFile().getFileType();
					switch (fileType) {
					case Common.FT_IMG:
						bindViewSentImage(cursor, holder, um, thumbnailImg);
						break;
					case Common.FT_AUDIO:
						bindViewSentAudio(cursor, holder, um, thumbnailImg);
						break;
					case Common.FT_VIDEO:
						bindViewSentVideo(cursor, holder, um, thumbnailImg);
						break;
					case Common.FT_PROFILE_IMG:	// not in the case
					default:	// unknown Type
						bindViewSentUnknown(cursor, holder, um, thumbnailImg);
						break;
					}
				} else {
					holder.textSndContent.setVisibility(View.VISIBLE);
					holder.textSndContent.setText("Unknown Content");
					holder.imageSndContent.setVisibility(View.GONE);
				}
			} catch (InvalidProtocolBufferMicroException e) {
				MTalkLogWriter.e(e);
			}

			RichString.enrich(holder.textSndContent);
			holder.textSndContent.setFocusable(false);

			// 보낸 메시지 상태 확인 아이콘 설정 ( 수신확인, 전송, 전송중, 전송실패 )
			setSentCondition(cursor, holder);
			return;
		} else { // 받은 메시지일 때.
			holder.parentSnd.setVisibility(View.GONE);
			holder.textSystem.setVisibility(View.GONE);
			holder.parentRcv.setVisibility(View.VISIBLE);
			holder.seekbarRcvProgress.setVisibility(View.GONE);

			// 수신 시간을 나타내어 준다.
			try {
				holder.textRcvTime.setText(TimeAdapter.Date2Str(new Date(msgTime), "kk:mm"));
			} catch (NullPointerException e1) {
				MTalkLogWriter.e(e1);
				// 컴파일 시간에 해결해야 한다.
			} catch (IllegalArgumentException e2) {
				MTalkLogWriter.e(e2);
				// 시간 표시 안 하면 된다.
			}

			// 내용 설정하기
			try {
				final int message = cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE);
				final UserMessage um = Common.UserMessage.parseFrom(cursor.getBlob(message));

				// 프로필을 설정한다.
				bindViewProfile(holder, um);
				// 버블 색상 지정
				bindViewReceivedBalloonColor(holder, um);

				int contentType = um.getContentType();
				if (contentType == Common.CONTENT_TYPE_PLAIN) {
					bindViewReceivedText(cursor, holder, um);
				} else if (contentType == Common.CONTENT_TYPE_ATTACHMENT && um.hasAttachment()) {
					final Attachment attachment = um.getAttachment();
					String mimeType = attachment.getMimeType();
					if (MTalkConstant.MIME_TYPE_VCARD.equals(mimeType)) {
						bindViewReceivedVcard(cursor, holder, um, thumbnailImg);
					} else if (MTalkConstant.MIME_TYPE_VCALENDAR.equals(mimeType)) {
						bindViewReceivedVcalendar(cursor, holder, um, thumbnailImg);
					} else if (MTalkConstant.MIME_TYPE_GEOTAG.equals(mimeType)) {
						bindViewReceivedVgeotag(cursor, holder, um, thumbnailImg);
					} else {
						holder.textRcvContent.setVisibility(View.VISIBLE);
						holder.textRcvContent.setText(R.string.attachment_unknown);
						holder.imageRcvContent.setVisibility(View.GONE);
					}					
				} else if(contentType == Common.CONTENT_TYPE_HTML && um.hasAttachFile()) {
					holder.textRcvContent.setVisibility(View.VISIBLE);
					holder.imageRcvContent.setVisibility(View.VISIBLE);
					holder.seekbarRcvProgress.setVisibility(View.GONE);
					int fileType = um.getAttachFile().getFileType();
					switch(fileType){
					case Common.FT_IMG:
						bindViewReceivedImage(cursor, holder, um, thumbnailImg);
						break;
					case Common.FT_AUDIO:
						bindViewReceivedAudio(cursor, holder, um, thumbnailImg);
						break;
					case Common.FT_VIDEO:
						bindViewReceivedVideo(cursor, holder, um, thumbnailImg);
						break;
					case Common.FT_PROFILE_IMG:
					default:
						bindViewReceivedUnknown(cursor, holder, um, thumbnailImg);
						break;
					}
				} else {
					holder.textRcvContent.setVisibility(View.VISIBLE);
					holder.textRcvContent.setText("Unknown Content");
					holder.imageRcvContent.setVisibility(View.GONE);
				}
			} catch (InvalidProtocolBufferMicroException e) {
				MTalkLogWriter.e(e);
			}

			RichString.enrich(holder.textRcvContent);
			return;
		}
	}

	protected void bindViewTime(Cursor cursor, BalloonHolder holder,
			final long msgTime) {
		int cursorPosition = cursor.getPosition();
		if(cursorPosition != 0){
			cursor.moveToPosition(cursorPosition-1);
			mDateTime = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_TIME));
			cursor.moveToNext();
		}
		if(cursorPosition == 0){
			holder.textDate.setVisibility(View.VISIBLE);
			holder.textDate.setText(TimeAdapter.Date2Str(new Date(msgTime), "yyyy-MM-dd"));
			mDateTime = msgTime;
		}else{
			switch(TimeAdapter.CompareTimeLong(mDateTime, msgTime)){
			case TimeAdapter.DATE_CHANGED_NONE:
				holder.textDate.setVisibility(View.GONE);
				break;
			case TimeAdapter.DATE_CHANGED_MONTH:
			case TimeAdapter.DATE_CHANGED_WEEK:
			case TimeAdapter.DATE_CHANGED_YEAR:
			case TimeAdapter.DATE_CHANGED_DAY_ONE:
			case TimeAdapter.DATE_CHANGED_DAY_TWO:
			case TimeAdapter.DATE_CHANGED_DAY_THREE:
			case TimeAdapter.DATE_CHANGED_DAY_FOUR:
			case TimeAdapter.DATE_CHANGED_DAY_FIVE:
			case TimeAdapter.DATE_CHANGED_DAY_SIX:
				holder.textDate.setVisibility(View.VISIBLE);
				holder.textDate.setText(TimeAdapter.Date2Str(new Date(msgTime), "yyyy-MM-dd"));
				break;
			default:
				holder.textDate.setVisibility(View.GONE);
				break;
			}
		}
	}

	protected void bindViewSystemMessage(Cursor cursor, BalloonHolder holder) {
		final int message = cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE);

		// 시스템 메시지일 때
		holder.parentRcv.setVisibility(View.GONE);
		holder.parentSnd.setVisibility(View.GONE);
		SystemMessage sm;
		try{
			sm = Common.SystemMessage.parseFrom(cursor.getBlob(message));
			String param1List = " ";
			String param2List = " ";
			String param3List = " ";
			for(SystemMessageOption smo : sm.getSystemMessageOptionList()){
				for(int i = 0; i < smo.getParam1Count(); i++){
					if(i == 0){
						param1List = smo.getParam1(i);
					}else{
						param1List = param1List + ", " + smo.getParam1(i);
					}
				}
				for(int i = 0; i < smo.getParam2Count(); i++){
					if(i == 0){
						param2List = smo.getParam2(i);
					}else{
						param2List = param2List + ", " + smo.getParam2(i);
					}
				}
				for(int i = 0; i < smo.getParam3Count(); i++){
					if(i == 0){
						param3List = smo.getParam3(i);
					}else{
						param3List = param3List + ", " + smo.getParam3(i);
					}
				}
			}			

			switch(sm.getType()){
			case Common.SYS_MSG_TYPE_MEMBER_ADDED:
				String smContentAdded = mContext.getString(R.string.chat_system_message_add_format);
				smContentAdded = smContentAdded.replaceAll("#S", param1List);
				smContentAdded = smContentAdded.replaceAll("#R", param2List);
				holder.textSystem.setVisibility(View.VISIBLE);
				holder.textSystem.setText(smContentAdded);
				break;
			case Common.SYS_MSG_TYPE_MEMBER_REMOVED:
				String smContentRemoved = mContext.getString(R.string.chat_system_message_remove_format);
				smContentRemoved = smContentRemoved.replaceAll("#L", param1List);
				holder.textSystem.setVisibility(View.VISIBLE);
				holder.textSystem.setText(smContentRemoved);
				break;
			default:
				holder.textSystem.setVisibility(View.GONE);
				break;
			}
		}catch (InvalidProtocolBufferMicroException e){
			MTalkLogWriter.e(e);
		}
	}

	protected void bindViewControlMessage(Cursor cursor, BalloonHolder holder) {
		final int message = cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE);

		// 컨트롤 메시지 일때. ReadMark?
		holder.parentRcv.setVisibility(View.GONE);
		holder.parentSnd.setVisibility(View.GONE);
		ControlMessage cm;
		try{
			cm = Common.ControlMessage.parseFrom(cursor.getBlob(message));
			cm.getType();
			for(int i=0; i < cm.getMessageRemovedOptionCount(); i++){
				cm.getMessageRemovedOption(i);
			}
			holder.textSystem.setVisibility(View.GONE);
		}catch(InvalidProtocolBufferMicroException e){
			MTalkLogWriter.e(e);
		}
	}

	protected Bitmap bindViewThumbnail(Cursor cursor, BalloonHolder holder,
			final int thumbnailColumn) {
		Bitmap thumbnailImg = null;
		if(cursor.getBlob(thumbnailColumn) != null){
			try {
				FileTransferInfo thumbnailInfo = FileTransferInfo.parseFrom(cursor.getBlob(thumbnailColumn));

				// Thumbnail 이 있을경우.
				if(thumbnailInfo != null && thumbnailInfo.hasFileUri()
						&& thumbnailInfo.getState() == Database.SENDING_MESSAGE){
					File thumbFile = new File(thumbnailInfo.getFileUri());
					if (thumbFile.exists() && thumbFile.canRead()) {
						thumbnailImg = BitmapFactory.decodeStream(new FileInputStream(thumbFile));
						//MTalkLogWriter.v("ChatListCursorAdapter.bindView(): thumbnail is. well done.");
					} else {
						//MTalkLogWriter.w("ChatListCursorAdapter.bindView(): thumbnail not assigned.");
					}
				}
			} catch (InvalidProtocolBufferMicroException e) {
				MTalkLogWriter.e(e);
			} catch (FileNotFoundException e) {
				MTalkLogWriter.e(e);
			}
		}else{
			thumbnailImg = null;
		}
		return thumbnailImg;
	}

	protected void bindViewSentText(Cursor cursor, BalloonHolder holder, final UserMessage um) {
		final long clientViewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_MSB));
		final long clientViewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_LSB));
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long clientMsgUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_MSB));
		final long clientMsgUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final UUID clientMsgUuid = GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb);
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS)); 

		// 보여주기
		holder.textSndContent.setVisibility(View.VISIBLE);
		holder.textSndContent.setText(um.getContent());
		holder.imageSndContent.setVisibility(View.GONE);
		// 롱클릭
		OnLongClickListener longClickListener = new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		};
		holder.lLayoutSndContent.setOnLongClickListener(longClickListener);
		holder.textSndContent.setOnLongClickListener(longClickListener);
		holder.imageSndContent.setOnLongClickListener(longClickListener);
		// 클릭 - 전송 상태 배지
		holder.imageAlert.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				new AlertDialog.Builder(mContext)
				.setMessage(R.string.attachment_retransfer)
				.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				})
				.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						SendMessageReq sendMessageReq = new SendMessageReq();
						sendMessageReq.setViewUuid(InboxDatabaseHelper.getViewUUID(mContext, clientViewUuidMsb, clientViewUuidLsb));
						sendMessageReq.setMessage(um);

						ChatDatabaseHelper.updateMessageStatus(mContext, clientMsgUuid, MessageStatus.SENDING.ordinal());

						SendMessageTask task = new SendMessageTask(mContext, null, sendMessageReq, clientViewUuidMsb, clientViewUuidLsb, clientMsgUuid);
						task.execute();
						dialog.dismiss();
					}
				})
				.create()
				.show();
			}
		});
	}

	protected void bindViewSentVcard(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		final long clientViewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_MSB));
		final long clientViewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_LSB));
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long clientMsgUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_MSB));
		final long clientMsgUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final UUID clientMsgUuid = GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb);
		final Attachment attachment = um.getAttachment();
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		// 보여주기
		holder.textSndContent.setVisibility(View.VISIBLE);
		holder.textSndContent.setText(attachment.getFileName());
		holder.imageSndContent.setVisibility(View.VISIBLE);
		holder.imageSndContent.setImageResource(R.drawable.ic_attachment_vcard);
		// 롱클릭
		OnLongClickListener longClickListener = new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		};
		holder.lLayoutSndContent.setOnLongClickListener(longClickListener);
		holder.textSndContent.setOnLongClickListener(longClickListener);
		holder.imageSndContent.setOnLongClickListener(longClickListener);
		// 클릭
		OnClickListener clickListener = new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent intent = new Intent(mContext, VCardReadActivity.class);
				intent.putExtra(VCardReadActivity.INTENT_MESSAGE_UUID_MSB, clientMsgUuidMsb);
				intent.putExtra(VCardReadActivity.INTENT_MESSAGE_UUID_LSB, clientMsgUuidLsb);
				mContext.startActivity(intent);
			}
		};
		holder.lLayoutSndContent.setOnClickListener(clickListener);
		holder.textSndContent.setOnClickListener(clickListener);
		holder.imageSndContent.setOnClickListener(clickListener);
		// 클릭 - 전송 상태 배지
		holder.imageAlert.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				new AlertDialog.Builder(mContext)
				.setMessage(R.string.attachment_retransfer)
				.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				})
				.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						SendMessageReq sendMessageReq = new SendMessageReq();
						sendMessageReq.setViewUuid(InboxDatabaseHelper.getViewUUID(mContext, clientViewUuidMsb, clientViewUuidLsb));
						sendMessageReq.setMessage(um);

						ChatDatabaseHelper.updateMessageStatus(mContext, clientMsgUuid, MessageStatus.SENDING.ordinal());

						SendMessageTask task = new SendMessageTask(mContext, null, sendMessageReq, clientViewUuidMsb, clientViewUuidLsb, clientMsgUuid);
						task.execute();
						dialog.dismiss();
					}
				})
				.create()
				.show();
			}
		});
	}

	protected void bindViewSentVcalendar(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		final long clientViewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_MSB));
		final long clientViewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_LSB));
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long clientMsgUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_MSB));
		final long clientMsgUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final UUID clientMsgUuid = GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb);
		final Attachment attachment = um.getAttachment();
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		// 보여주기
		holder.textSndContent.setText(attachment.getFileName());
		holder.imageSndContent.setImageResource(R.drawable.ic_attachment_vcalendar);
		// 롱클릭
		OnLongClickListener longClickListener = new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		};
		holder.lLayoutSndContent.setOnLongClickListener(longClickListener);
		holder.textSndContent.setOnLongClickListener(longClickListener);
		holder.imageSndContent.setOnLongClickListener(longClickListener);
		// 클릭
		OnClickListener clickListener = new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent intent = new Intent(mContext, ReadVCalendarActivity.class);
				intent.putExtra(ReadVCalendarActivity.INTENT_MESSAGE_UUID_MSB, clientMsgUuidMsb);
				intent.putExtra(ReadVCalendarActivity.INTENT_MESSAGE_UUID_LSB, clientMsgUuidLsb);
				mContext.startActivity(intent);
			}
		};
		holder.lLayoutSndContent.setOnClickListener(clickListener);
		holder.textSndContent.setOnClickListener(clickListener);
		holder.imageSndContent.setOnClickListener(clickListener);
		// 클릭 - 전송 상태 배지
		holder.imageAlert.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				new AlertDialog.Builder(mContext)
				.setMessage(R.string.attachment_retransfer)
				.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				})
				.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						SendMessageReq sendMessageReq = new SendMessageReq();
						sendMessageReq.setViewUuid(InboxDatabaseHelper.getViewUUID(mContext, clientViewUuidMsb, clientViewUuidLsb));
						sendMessageReq.setMessage(um);

						ChatDatabaseHelper.updateMessageStatus(mContext, clientMsgUuid, MessageStatus.SENDING.ordinal());

						SendMessageTask task = new SendMessageTask(mContext, null, sendMessageReq, clientViewUuidMsb, clientViewUuidLsb, clientMsgUuid);
						task.execute();
						dialog.dismiss();
					}
				})
				.create()
				.show();
			}
		});
	}

	protected void bindViewSentGeotag(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		final long clientViewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_MSB));
		final long clientViewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_LSB));
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long clientMsgUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_MSB));
		final long clientMsgUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final UUID clientMsgUuid = GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb);
		final Attachment attachment = um.getAttachment();
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		// 보여주기
		holder.textSndContent.setText(attachment.getFileName());
		if(thumbnailImg != null){
			holder.imageSndContent.setImageBitmap(thumbnailImg);
		}else{
			holder.imageSndContent.setImageResource(R.drawable.ic_attachment_geotag);
		}
		// 롱클릭
		OnLongClickListener longClickListener = new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		};
		holder.lLayoutSndContent.setOnLongClickListener(longClickListener);
		holder.textSndContent.setOnLongClickListener(longClickListener);
		holder.imageSndContent.setOnLongClickListener(longClickListener);
		// 클릭
		OnClickListener clickListener = new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent i = new Intent(mContext, GeotagActivity.class);
				i.putExtra(GeotagActivity.KEY_GEOPOINT, attachment.getContent().toStringUtf8());
				mContext.startActivity(i);
			}
		};
		holder.lLayoutSndContent.setOnClickListener(clickListener);
		holder.textSndContent.setOnClickListener(clickListener);
		holder.imageSndContent.setOnClickListener(clickListener);
		// 클릭 - 전송 상태 배지
		holder.imageAlert.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				new AlertDialog.Builder(mContext)
				.setMessage(R.string.attachment_retransfer)
				.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						dialog.dismiss();
					}
				})
				.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						SendMessageReq sendMessageReq = new SendMessageReq();
						sendMessageReq.setViewUuid(InboxDatabaseHelper.getViewUUID(mContext, clientViewUuidMsb, clientViewUuidLsb));
						sendMessageReq.setMessage(um);

						ChatDatabaseHelper.updateMessageStatus(mContext, clientMsgUuid, MessageStatus.SENDING.ordinal());

						SendMessageTask task = new SendMessageTask(mContext, null, sendMessageReq, clientViewUuidMsb, clientViewUuidLsb, clientMsgUuid);
						task.execute();
						dialog.dismiss();
					}
				})
				.create()
				.show();
			}
		});
	}

	protected void bindViewSentImage(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		try {
			final long clientViewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_MSB));
			final long clientViewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_LSB));
			final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
			final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
			final long clientMsgUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_MSB));
			final long clientMsgUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_LSB));
			final long messageUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_MSB));
			final long messageUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_LSB));
			final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
			final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
			final UUID clientMsgUuid = GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb);
			final int fileTransferInfo = cursor.getColumnIndexOrThrow(MessageTable.KEY_FILE_TRANSFER_INFO);
			byte[] transeferInfoBytes = cursor.getBlob(fileTransferInfo);
			final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

			// 전송상태에 따라 어떻게 해야 하는지를 먼저 정하자.
			OnLongClickListener longClickListener = null;
			OnClickListener clickListener = null;
			OnClickListener badgeClickListener = null;
			String lazyLoadUri = null;
			if (transeferInfoBytes == null) {
				/* 아마 작업중 시간차에 의해 이 분기로 들어올텐데, 이 경우엔 Uri 정보가 없기 때문에 파일로부터 섬네일을 받을 수 없다.
				 * 
				 * 무슨 이유에서건 이 시점에 파일 전송이 중단되어 있는 경우가 있을 수 있다.
				 * 그렇다면 이 경우에 보여줘야 하는 것은 전송 실패 상태를 나타내는 진행바이다.
				 * 
				 * Uri를 얻을 수 없기 때문에 재전송을 할 수 없다. 따라서 전송 상태 배지도 아무 일도 할 수 없다.
				 * */
				longClickListener = new OnLongClickListener() {
					@Override
					public boolean onLongClick(View v) {
						return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
								GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
								status, clientMsgUuid);
					}
				};
				clickListener = null;
				badgeClickListener = null;
			} else {
				final FileTransferInfo fileTranInfo = FileTransferInfo.parseFrom(transeferInfoBytes);

				// 어떻게 보여줄지 정하기
				if (fileTranInfo != null && fileTranInfo.getFileUri() != null) {	// 가능할 경우 파일로부터 손톱그림을 구성한다.
					lazyLoadUri = fileTranInfo.getFileUri();	// url만 빼 놓고 지연된 로딩을 해야 한다.
				}
				boolean resendable = false;
				if(fileTranInfo != null
						&& fileTranInfo.hasWorking() 
						&& fileTranInfo.hasNumOfSlice()
						&& fileTranInfo.hasSliceNo() 
						&& fileTranInfo.hasState()) {

					if (fileTranInfo.getWorking()) {	// 작업중이다.
						holder.seekbarSndProgress.setVisibility(View.VISIBLE);
						switch (fileTranInfo.getState()) {
						case Database.RECEIVED_TOKEN:
						case Database.VALIDATED:
							holder.seekbarSndProgress.setProgress(0);
							holder.seekbarSndProgress.setSecondaryProgress(0);
							resendable = false;
							break;
						case Database.SENDING_SLICE:
							holder.seekbarSndProgress.setProgress(((fileTranInfo.getSliceNo()+1)*holder.seekbarSndProgress.getMax())/(fileTranInfo.getNumOfSlice()));
							holder.seekbarSndProgress.setSecondaryProgress(0);
							resendable = false;
							break;
						case Database.SENDING_MESSAGE:
							holder.seekbarSndProgress.setProgress(holder.seekbarSndProgress.getMax());
							holder.seekbarSndProgress.setSecondaryProgress(0);
							resendable = false;
							break;
						case Database.NONE:
						default:
							holder.seekbarSndProgress.setProgress(0);
							holder.seekbarSndProgress.setSecondaryProgress(holder.seekbarSndProgress.getMax());
							resendable = false;
							break;
						}
					} else {	// 작업중이 아니다.
						holder.seekbarSndProgress.setVisibility(View.VISIBLE);
						switch (fileTranInfo.getState()) {
						case Database.RECEIVED_TOKEN:
						case Database.VALIDATED:
							holder.seekbarSndProgress.setProgress(0);
							holder.seekbarSndProgress.setSecondaryProgress(holder.seekbarSndProgress.getMax());
							resendable = true;
							break;
						case Database.SENDING_SLICE:
							holder.seekbarSndProgress.setProgress(((fileTranInfo.getSliceNo()+1)*holder.seekbarSndProgress.getMax())/(fileTranInfo.getNumOfSlice()));
							holder.seekbarSndProgress.setSecondaryProgress(holder.seekbarSndProgress.getMax());
							resendable = true;
							break;
						case Database.SENDING_MESSAGE:
							// 끝난 경우
							holder.seekbarSndProgress.setVisibility(View.GONE);
							resendable = false;
							break;
						case Database.NONE:
						default:
							holder.seekbarSndProgress.setProgress(0);
							holder.seekbarSndProgress.setSecondaryProgress(holder.seekbarSndProgress.getMax());
							resendable = true;
							break;
						}
					}
				}else{
					holder.seekbarSndProgress.setVisibility(View.GONE);
					resendable = false;
				}
				// 롱클릭시 뭘 할지 정하기
				longClickListener = new OnLongClickListener() {
					@Override
					public boolean onLongClick(View v) {
						return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
								GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
								status, clientMsgUuid);
					}
				};
				// 클릭시 뭘 할지 정하기
				final boolean imageResendable = resendable;
				clickListener = new OnClickListener() {
					@Override
					public void onClick(View v) {
						if (imageResendable) {
							// 재전송 승인 팝업
							new AlertDialog.Builder(mContext)
							.setMessage(R.string.attachment_retransfer)
							.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									// 그냥 닫기
									dialog.dismiss();
								}
							})
							.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									// 이어보내기
									try {
										FileUploadTask task = new FileUploadTask(mContext, mHandler,
												GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb),
												GpbSupport.makeUuidMsg(messageUuidMsb, messageUuidLsb),
												clientMsgUuid, fileTranInfo, Common.FT_IMG);
										task.execute();
									} catch (Exception e) {
										MTalkLogWriter.e(e);
									}
									dialog.dismiss();
								}
							})
							.create()
							.show();
						} else {
							// 이미지 보여주기
							Intent intent = new Intent();
							intent.setAction(android.content.Intent.ACTION_VIEW);
							intent.setDataAndType(Uri.fromFile(new File(fileTranInfo.getFileUri())), "image/*");
							mActivity.startActivity(intent);
						}
					}
				};
				// 배지 클릭시 뭘 할지 정하기
				badgeClickListener = new OnClickListener() {
					@Override
					public void onClick(View v) {
						// 이어보내기 확인 질문
						new AlertDialog.Builder(mContext)
						.setMessage(R.string.attachment_retransfer)
						.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int which) {
								// 그냥 닫기
								dialog.dismiss();
							}
						})
						.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int which) {
								// 이어보내기
								try {
									new FileUploadTask(mContext, mHandler,
											GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb),
											GpbSupport.makeUuidMsg(messageUuidMsb, messageUuidLsb),
											clientMsgUuid, fileTranInfo, Common.FT_IMG)
									.execute();
								} catch (Exception e) {
									MTalkLogWriter.e(e);
								}
								dialog.dismiss();
							}
						})
						.create()
						.show();
					}
				};
			}
			// 여기까지 다 정했으면...

			// 보여주기
			holder.textSndContent.setText(R.string.attachment_image_name);
			if (thumbnailImg != null) {
				holder.imageSndContent.setImageBitmap(thumbnailImg);
			} else {
				holder.imageSndContent.setImageResource(R.drawable.test_pic);
				// 엉뚱한 이미지가 세팅되어 있을 수 있다. 지연된 로딩 동안에도 임시로 기본 그림을 띄워주어야 한다.
				if (lazyLoadUri != null) {
					loadImageViewLazy(holder.imageSndContent, clientMsgUuid, lazyLoadUri);
				}
			}
			// 롱클릭
			if (longClickListener != null) {
				holder.lLayoutSndContent.setOnLongClickListener(longClickListener);
				holder.textSndContent.setOnLongClickListener(longClickListener);
				holder.imageSndContent.setOnLongClickListener(longClickListener);
			}
			// 클릭
			if (clickListener != null) {
				holder.imageSndContent.setOnClickListener(clickListener);
			}
			// 클릭 - 전송 상태 배지
			if (badgeClickListener != null) {
				holder.imageAlert.setOnClickListener(badgeClickListener);
			}
		} catch (Exception e) {
			MTalkLogWriter.e(e);
		}
	}

	protected void bindViewSentAudio(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		final long clientViewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_MSB));
		final long clientViewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_LSB));
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long clientMsgUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_MSB));
		final long clientMsgUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_LSB));
		final long messageUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_MSB));
		final long messageUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final UUID clientMsgUuid = GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb);
		final int fileTransferInfo = cursor.getColumnIndexOrThrow(MessageTable.KEY_FILE_TRANSFER_INFO);
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		holder.textSndContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		});
		holder.lLayoutSndContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		});
		byte[] transeferInfoBytes = cursor.getBlob(fileTransferInfo);
		if (transeferInfoBytes == null) {
			holder.textSndContent.setText(R.string.attachment_audio_name);
			holder.imageSndContent.setVisibility(View.GONE);
		} else {
			try {
				final FileTransferInfo fileTranInfo = FileTransferInfo.parseFrom(cursor.getBlob(fileTransferInfo));
				boolean resendable = false;
				if(fileTranInfo != null 
						&& fileTranInfo.hasWorking() 
						&& fileTranInfo.hasNumOfSlice()
						&& fileTranInfo.hasSliceNo() 
						&& fileTranInfo.hasState()){
					holder.seekbarSndProgress.setVisibility(View.VISIBLE);

					if(fileTranInfo.getWorking()){
						// 작업중이다.
						if(fileTranInfo.getState() == Database.SENDING_MESSAGE){
							// 작업이 끝났다! 사라져 버려!
							holder.seekbarSndProgress.setVisibility(View.GONE);
						}else if(fileTranInfo.getSliceNo() < 0 || fileTranInfo.getNumOfSlice() <= 0){
							// 시작도 안했다.
							holder.seekbarSndProgress.setVisibility(View.GONE);	
						}else if(fileTranInfo.getState() == Database.SENDING_SLICE){
							// 작업 진행중!! 진행 상황을 보고 하자!
							holder.seekbarSndProgress.setVisibility(View.VISIBLE);
							// WEIGHT dip 갯수만큼 쪼개자.( (((진행갯수(ZeroBase))+1)/총갯수) * dip 갯수)
							int progress = ((fileTranInfo.getSliceNo()+1)*100)/(fileTranInfo.getNumOfSlice());
							holder.seekbarSndProgress.setProgress(progress);
						}else{
							holder.seekbarSndProgress.setVisibility(View.GONE);	
						}
					}else if(fileTranInfo.hasState()){
						if(fileTranInfo.getSliceNo() < 0 || fileTranInfo.getNumOfSlice() <= 0){
							// 시작도 안했다.
							holder.seekbarSndProgress.setVisibility(View.GONE);	
						}else if(fileTranInfo.getState() != Database.SENDING_MESSAGE){
							// 다시 전송해야 된다. 알려줘야 됨.
							holder.seekbarSndProgress.setVisibility(View.VISIBLE);
							holder.seekbarSndProgress.setSecondaryProgress(holder.seekbarSndProgress.getMax());
							int progress = ((fileTranInfo.getSliceNo()+1)*100)/(fileTranInfo.getNumOfSlice());
							holder.seekbarSndProgress.setProgress(progress);
							resendable = true;
						} else {
							// 이미 끝나 있는 작업
							holder.seekbarSndProgress.setVisibility(View.GONE);
						}
					}
				}else{
					holder.seekbarSndProgress.setVisibility(View.GONE);
				}
				holder.textSndContent.setText(R.string.attachment_audio_name);
				// 섬네일 설정
				if(thumbnailImg != null){
					holder.imageSndContent.setImageBitmap(thumbnailImg);
				}else{
					holder.imageSndContent.setImageResource(R.drawable.test_voice);
				}
				// 보낸 오디오 클릭 이벤트
				holder.imageSndContent.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						GpbSupport.makeUuid(messageUuidMsb, messageUuidLsb);
					}
				});
				// 메시지를 재전송할 것인지 삭제할 것인지 묻는다. 
				holder.imageAlert.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						new AlertDialog.Builder(mContext)
						.setMessage(R.string.attachment_retransfer)
						.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int which) {
								dialog.dismiss();
							}
						})
						.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int which) {
								try {
									FileUploadTask task;
									try {
										task = new FileUploadTask(mContext, mHandler,
												GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb),
												GpbSupport.makeUuidMsg(messageUuidMsb, messageUuidLsb),
												clientMsgUuid, fileTranInfo, Common.FT_IMG);
										task.execute();
									} catch (FileNotFoundException e) {
										MTalkLogWriter.e(e);
									}
								} catch (SecurityException e) {
									MTalkLogWriter.e(e);
								}
								dialog.dismiss();
							}
						})
						.create()
						.show();
					}
				});
			} catch (InvalidProtocolBufferMicroException e1) {
				MTalkLogWriter.e(e1);
			}
		}
	}

	protected void bindViewSentVideo(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		final long clientViewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_MSB));
		final long clientViewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_LSB));
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long clientMsgUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_MSB));
		final long clientMsgUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_LSB));
		final long messageUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_MSB));
		final long messageUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final UUID clientMsgUuid = GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb);
		final int fileTransferInfo = cursor.getColumnIndexOrThrow(MessageTable.KEY_FILE_TRANSFER_INFO);
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		holder.textSndContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		});
		holder.lLayoutSndContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		});
		byte[] transeferInfoBytes = cursor.getBlob(fileTransferInfo);
		if (transeferInfoBytes == null) {
			// 아직 키만 가지고 있음. 누르면 다운로드.
			holder.textSndContent.setText(R.string.attachment_video_name);
			if(thumbnailImg != null){
				holder.imageSndContent.setImageBitmap(thumbnailImg);
			}else {
				holder.imageSndContent.setImageResource(R.drawable.test_camera);
			}
			holder.imageSndContent.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					new AlertDialog.Builder(mContext)
					.setMessage(R.string.attachment_download)
					.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
						}
					})
					.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							try {
								FileDownloadTask task = new FileDownloadTask(mContext, mHandler,
										GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb),
										GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb),
										um.getAttachFile(), null);
								task.execute();
							} catch (SecurityException e) {
								MTalkLogWriter.e(e);
							}
							dialog.dismiss();
						}
					})
					.create()
					.show();
				}
			});
		} else {
			try {
				final FileTransferInfo fileTranInfo = FileTransferInfo.parseFrom(cursor.getBlob(fileTransferInfo));
				boolean resendable = false;
				if(fileTranInfo != null 
						&& fileTranInfo.hasWorking() 
						&& fileTranInfo.hasNumOfSlice()
						&& fileTranInfo.hasSliceNo() 
						&& fileTranInfo.hasState()){
					holder.seekbarSndProgress.setVisibility(View.VISIBLE);

					if(fileTranInfo.getWorking()){
						// 작업중이다.
						if(fileTranInfo.getState() == Database.SENDING_MESSAGE){
							// 작업이 끝났다! 사라져 버려!
							holder.seekbarSndProgress.setVisibility(View.GONE);
						}else if(fileTranInfo.getSliceNo() < 0 || fileTranInfo.getNumOfSlice() <= 0){
							// 시작도 안했다.
							holder.seekbarSndProgress.setVisibility(View.GONE);	
						}else if(fileTranInfo.getState() == Database.SENDING_SLICE){
							// 작업 진행중!! 진행 상황을 보고 하자!
							holder.seekbarSndProgress.setVisibility(View.VISIBLE);
							// WEIGHT dip 갯수만큼 쪼개자.( (((진행갯수(ZeroBase))+1)/총갯수) * dip 갯수)
							int progress = ((fileTranInfo.getSliceNo()+1)*100)/(fileTranInfo.getNumOfSlice());
							holder.seekbarSndProgress.setProgress(progress);
						}else{
							holder.seekbarSndProgress.setVisibility(View.GONE);	
						}
					}else if(fileTranInfo.hasState()){
						if(fileTranInfo.getSliceNo() < 0 || fileTranInfo.getNumOfSlice() <= 0){
							// 시작도 안했다.
							holder.seekbarSndProgress.setVisibility(View.GONE);	
						}else if(fileTranInfo.getState() != Database.SENDING_MESSAGE){
							// 다시 전송해야 된다. 알려줘야 됨.
							holder.seekbarSndProgress.setVisibility(View.VISIBLE);
							holder.seekbarSndProgress.setSecondaryProgress(holder.seekbarSndProgress.getMax());
							int progress = ((fileTranInfo.getSliceNo()+1)*100)/(fileTranInfo.getNumOfSlice());
							holder.seekbarSndProgress.setProgress(progress);
							resendable = true;
						} else {
							// 이미 끝나 있는 작업
							holder.seekbarSndProgress.setVisibility(View.GONE);
						}
					}
				}else{
					holder.seekbarSndProgress.setVisibility(View.GONE);
				}
				holder.textSndContent.setText(R.string.attachment_video_name);

				// 섬네일 설정
				Bitmap thumbnail = GraphicUtil.getVideoFrame(fileTranInfo.getFileUri());
				if (thumbnail != null) {	//###
					try{
						holder.imageSndContent.setImageBitmap(ImageManager.getResizedBitmap(thumbnail,
								(int) Dip.toPixel(THUMB_MAX_SIZE_DIP)));
					} catch (Exception e) {
						MTalkLogWriter.e(e);
						holder.imageSndContent.setImageResource(R.drawable.test_camera);
					}
				}else if(thumbnailImg != null){

					holder.imageSndContent.setImageBitmap(thumbnailImg);
				}else {
					holder.imageSndContent.setImageResource(R.drawable.test_camera);
				}

				// 보낸 비디오 클릭 이벤트
				final boolean videoResendable = resendable;
				holder.imageSndContent.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						if (videoResendable) {
							new AlertDialog.Builder(mContext)
							.setMessage(R.string.attachment_retransfer)
							.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									dialog.dismiss();
								}
							})
							.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									try {
										FileUploadTask task = new FileUploadTask(mContext, mHandler,
												GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb),
												GpbSupport.makeUuidMsg(messageUuidMsb, messageUuidLsb),
												clientMsgUuid, fileTranInfo, Common.FT_VIDEO);
										task.execute();
									} catch (SecurityException e) {
										MTalkLogWriter.e(e);
									} catch (FileNotFoundException e) {
										MTalkLogWriter.e(e);
									}
									dialog.dismiss();
								}
							})
							.create()
							.show();
						} else {
							// 비디오 보여주기
							Intent showMovie = new Intent(Intent.ACTION_VIEW);
							showMovie.setDataAndType(Uri.fromFile(new File(fileTranInfo.getFileUri())), "video/*");
							showMovie.putExtra(MediaStore.EXTRA_FINISH_ON_COMPLETION, false);
							mActivity.startActivity(showMovie);
						}
					}
				});
				// 메시지를 재전송할 것인지 삭제할 것인지 묻는다. 
				holder.imageAlert.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						new AlertDialog.Builder(mContext)
						.setMessage(R.string.attachment_retransfer)
						.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int which) {
								dialog.dismiss();
							}
						})
						.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
							@Override
							public void onClick(DialogInterface dialog, int which) {
								try {
									FileUploadTask task;
									try {
										task = new FileUploadTask(mContext, mHandler,
												GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb),
												GpbSupport.makeUuidMsg(messageUuidMsb, messageUuidLsb),
												clientMsgUuid, fileTranInfo, Common.FT_IMG);
										task.execute();
									} catch (FileNotFoundException e) {
										MTalkLogWriter.e(e);
									}
								} catch (SecurityException e) {
									MTalkLogWriter.e(e);
								}
								dialog.dismiss();
							}
						})
						.create()
						.show();
					}
				});
			} catch (InvalidProtocolBufferMicroException e1) {
				MTalkLogWriter.e(e1);
			}
		}
	}

	protected void bindViewSentUnknown(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		holder.textSndContent.setVisibility(View.VISIBLE);
		holder.textSndContent.setText(R.string.attachment_unknown);
		holder.imageSndContent.setVisibility(View.GONE);
	}

	protected void setSentCondition(Cursor cursor, BalloonHolder holder) {
		final int msgStatus = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		if(msgStatus == MessageTable.MessageStatus.CLIENT_RECEIVE.ordinal()){				
			holder.progressBalloon.setVisibility(View.GONE);
			holder.imageAlert.setVisibility(View.GONE);
			holder.chatSendStatus.setVisibility(View.GONE);
			holder.textUnreadCount.setVisibility(View.GONE);
		}else if(msgStatus == MessageTable.MessageStatus.SERVER_RECEIVE.ordinal()){
			holder.progressBalloon.setVisibility(View.GONE);
			holder.imageAlert.setVisibility(View.GONE);
			holder.chatSendStatus.setVisibility(View.VISIBLE);
			holder.textUnreadCount.setVisibility(View.GONE);
		}else if(msgStatus == MessageTable.MessageStatus.SENDING.ordinal()){
			holder.progressBalloon.setVisibility(View.VISIBLE);
			holder.imageAlert.setVisibility(View.GONE);
			holder.chatSendStatus.setVisibility(View.GONE);
			holder.textUnreadCount.setVisibility(View.VISIBLE);
			holder.textUnreadCount.setText("1");
		}else if(msgStatus == MessageTable.MessageStatus.SERVER_RECEIVE_FAIL.ordinal()){
			holder.progressBalloon.setVisibility(View.GONE);
			holder.imageAlert.setVisibility(View.VISIBLE);
			holder.chatSendStatus.setVisibility(View.GONE);
			holder.textUnreadCount.setVisibility(View.VISIBLE);
			holder.textUnreadCount.setText("0");
		}else{
			holder.progressBalloon.setVisibility(View.GONE);
			holder.imageAlert.setVisibility(View.GONE);
			holder.chatSendStatus.setVisibility(View.GONE);
			holder.textUnreadCount.setVisibility(View.GONE);
		}
	}

	protected void bindViewProfile(BalloonHolder holder, final UserMessage um) {
		if(um.hasSenderUuid()){
			ProfileImageLoader.getInstance(mContext).loadProfileImage(holder.imageProfile, 
					GpbSupport.UuidMsgToString(um.getSenderUuid()));
		}else{
			holder.imageProfile.setImageResource(R.drawable.onetoone_pic);
		}

		holder.imageProfile.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				ChatQuickActionItem item = BuddyDatabaseHelper.getChatBuddyInfo(mContext, um.getSenderUuid());
				if(item != null){
					setOnQuickAction(mContext, v, item.buddy_id, item.receiverMsb, item.receiverLsb, item.displayName, item.buddyInfo, item.raw_id, item.favorite);
				}
			}
		});
		holder.textName.setText(um.getSenderName());
	}

	protected void bindViewReceivedBalloonColor(BalloonHolder holder, final UserMessage um) {
		/*int uuidSecond = (int)GpbSupport.msbOf(um.getSenderUuid());
		switch((uuidSecond)%3){
			case 0:
				holder.lLayoutRcvContent.setBackgroundResource(R.drawable.ballon_default_blue);
				break;
			case 1:
				holder.lLayoutRcvContent.setBackgroundResource(R.drawable.ballon_mint);
				break;
			case 2:
				holder.lLayoutRcvContent.setBackgroundResource(R.drawable.ballon_orange);
				break;
			case 3:
				holder.lLayoutRcvContent.setBackgroundResource(R.drawable.ballon_yellow);
				break;
			default:
				holder.lLayoutRcvContent.setBackgroundResource(R.drawable.ballon_default_blue);
				break;
		}*/
		holder.lLayoutRcvContent.setBackgroundResource(GlobalPreferences.getBalloonColor());
	}

	protected void bindViewReceivedText(Cursor cursor, BalloonHolder holder, final UserMessage um) {
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		holder.textRcvContent.setVisibility(View.VISIBLE);
		holder.textRcvContent.setText(um.getContent());
		holder.textRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, null);
			}
		});
		holder.lLayoutRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, null);
			}
		});
		holder.imageRcvContent.setVisibility(View.GONE);
	}

	protected void bindViewReceivedVcard(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long messageUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_MSB));
		final long messageUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final Attachment attachment = um.getAttachment();
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		holder.textRcvContent.setVisibility(View.VISIBLE);
		holder.textRcvContent.setText(attachment.getFileName());
		holder.textRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, null);
			}
		});
		holder.lLayoutRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, null);
			}
		});
		holder.imageRcvContent.setVisibility(View.VISIBLE);
		if(thumbnailImg != null){
			holder.imageRcvContent.setImageBitmap(thumbnailImg);
		}else{
			holder.imageRcvContent.setImageResource(R.drawable.ic_attachment_vcard);
		}
		// 받은 첨부파일(VCARD) 클릭시 이벤트
		holder.imageRcvContent.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("ATOM", "vCard Click");
				Intent intent = new Intent(mContext, VCardReadActivity.class);
				intent.putExtra(VCardReadActivity.INTENT_MESSAGE_UUID_MSB, messageUuidMsb);
				intent.putExtra(VCardReadActivity.INTENT_MESSAGE_UUID_LSB, messageUuidLsb);
				mContext.startActivity(intent);
			}
		});
	}

	protected void bindViewReceivedVcalendar(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long messageUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_MSB));
		final long messageUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final Attachment attachment = um.getAttachment();
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		holder.textRcvContent.setVisibility(View.VISIBLE);
		holder.textRcvContent.setText(attachment.getFileName());
		holder.textRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, null);
			}
		});
		holder.lLayoutRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, null);
			}
		});
		holder.imageRcvContent.setVisibility(View.VISIBLE);			
		if(thumbnailImg != null){
			holder.imageRcvContent.setImageBitmap(thumbnailImg);
		}else{
			holder.imageRcvContent.setImageResource(R.drawable.ic_attachment_vcalendar);
		}
		// 받은 첨부파일(VCALENDAR) 클릭시 이벤트
		holder.imageRcvContent.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Log.i("ATOM", "VCALENDAR Click");
				Intent intent = new Intent(mContext, ReadVCalendarActivity.class);
				intent.putExtra(ReadVCalendarActivity.INTENT_MESSAGE_UUID_MSB, messageUuidMsb);
				intent.putExtra(ReadVCalendarActivity.INTENT_MESSAGE_UUID_LSB, messageUuidLsb);
				mContext.startActivity(intent);
			}
		});
	}

	protected void bindViewReceivedVgeotag(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long messageUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_MSB));
		final long messageUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final Attachment attachment = um.getAttachment();
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		holder.textRcvContent.setVisibility(View.VISIBLE);
		holder.textRcvContent.setText(attachment.getFileName());
		holder.textRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, null);
			}
		});
		holder.lLayoutRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, null);
			}
		});
		holder.imageRcvContent.setVisibility(View.VISIBLE);
		if(thumbnailImg != null){
			holder.imageRcvContent.setImageBitmap(thumbnailImg);
		}else{
			holder.imageRcvContent.setImageResource(R.drawable.ic_attachment_geotag);
		}
		// 받은 첨부파일(GEOTAG) 클릭시 이벤트
		holder.imageRcvContent.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent i = new Intent(mContext, GeotagActivity.class);
				i.putExtra(GeotagActivity.KEY_GEOPOINT, attachment.getContent().toStringUtf8());
				mContext.startActivity(i);
			}
		});
	}

	protected void bindViewReceivedImage(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		final long clientViewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_MSB));
		final long clientViewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_LSB));
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long clientMsgUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_MSB));
		final long clientMsgUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_LSB));
		final long messageUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_MSB));
		final long messageUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final UUID clientMsgUuid = GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb);
		final int fileTransferInfo = cursor.getColumnIndexOrThrow(MessageTable.KEY_FILE_TRANSFER_INFO);
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		holder.textRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		});
		holder.lLayoutRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		});
		byte[] transeferInfoBytes = cursor.getBlob(fileTransferInfo);
		if (transeferInfoBytes == null) {
			// 아직 키만 가지고 있음. 누르면 다운로드.
			if(thumbnailImg != null){
				holder.imageRcvContent.setImageBitmap(thumbnailImg);
			}else {
				holder.imageRcvContent.setImageResource(R.drawable.test_pic);
			}
			holder.textRcvContent.setText(R.string.attachment_image_name);
			holder.imageRcvContent.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					//GpbSupport.makeUuid(messageUuidMsb, messageUuidLsb);
					new AlertDialog.Builder(mContext)
					.setMessage(R.string.attachment_download)
					.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
						}
					})
					.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							try {
								FileDownloadTask task = new FileDownloadTask(mContext, mHandler,
										GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb),
										GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb),
										um.getAttachFile(), null);
								task.execute();
							} catch (SecurityException e) {
								MTalkLogWriter.e(e);
							}
							dialog.dismiss();
						}
					})
					.create()
					.show();
				}
			});
		} else {
			try {
				final FileTransferInfo fileTranInfo = FileTransferInfo.parseFrom(transeferInfoBytes);
				boolean resendable = false;
				if(fileTranInfo != null 
						&& fileTranInfo.hasWorking() 
						&& fileTranInfo.hasNumOfSlice()
						&& fileTranInfo.hasSliceNo() 
						&& fileTranInfo.hasState()){
					holder.seekbarRcvProgress.setVisibility(View.VISIBLE);

					if(fileTranInfo.getWorking()){
						// 작업중이다.
						if(fileTranInfo.getState() == Database.SENDING_MESSAGE){
							// 작업이 끝났다! 사라져 버려!
							holder.seekbarRcvProgress.setVisibility(View.GONE);
						}else if(fileTranInfo.getSliceNo() < 0 || fileTranInfo.getNumOfSlice() <= 0){
							// 시작도 안했다.
							holder.seekbarRcvProgress.setVisibility(View.GONE);	
						}else if(fileTranInfo.getState() == Database.SENDING_SLICE){
							// 작업 진행중!! 진행 상황을 보고 하자!
							holder.seekbarRcvProgress.setVisibility(View.VISIBLE);
							// WEIGHT dip 갯수만큼 쪼개자.( (((진행갯수(ZeroBase))+1)/총갯수) * dip 갯수)
							int progress = ((fileTranInfo.getSliceNo()+1)*100)/(fileTranInfo.getNumOfSlice());
							holder.seekbarRcvProgress.setProgress(progress);
						}else{
							holder.seekbarRcvProgress.setVisibility(View.GONE);	
						}
					}else if(fileTranInfo.hasState()){
						if(fileTranInfo.getSliceNo() < 0 || fileTranInfo.getNumOfSlice() <= 0){
							// 시작도 안했다.
							holder.seekbarRcvProgress.setVisibility(View.GONE);	
						}else if(fileTranInfo.getState() != Database.SENDING_MESSAGE){
							// 다시 전송해야 된다. 알려줘야 됨.
							holder.seekbarRcvProgress.setVisibility(View.VISIBLE);
							holder.seekbarRcvProgress.setSecondaryProgress(holder.seekbarRcvProgress.getMax());
							int progress = ((fileTranInfo.getSliceNo()+1)*100)/(fileTranInfo.getNumOfSlice());
							holder.seekbarRcvProgress.setProgress(progress);
							resendable = true;
						} else {
							// 이미 끝나 있는 작업
							holder.seekbarRcvProgress.setVisibility(View.GONE);
						}
					}
				}else{
					holder.seekbarRcvProgress.setVisibility(View.GONE);
				}
				holder.textRcvContent.setText(R.string.attachment_image_name);

				final boolean imageResendable = resendable;
				if(thumbnailImg != null){
					holder.imageRcvContent.setImageBitmap(thumbnailImg);
				}else if (! imageResendable) {	//###
					// 파일 다운로드가 완료되어 있는 경우
					try {								
						Bitmap floorThumb = ImageManager.getFloorThumbnail(new File(fileTranInfo.getFileUri()), (int) Dip.toPixel(THUMB_LOAD_SIZE_DIP));
						if (floorThumb != null) {
							holder.imageRcvContent.setImageBitmap(ImageManager.getResizedBitmap(floorThumb, (int) Dip.toPixel(THUMB_MAX_SIZE_DIP)));
						}
					} catch (Exception e) {
						MTalkLogWriter.e(e);
						holder.imageRcvContent.setImageResource(R.drawable.test_pic);
					}

				}else{
					holder.imageRcvContent.setImageResource(R.drawable.test_pic);
				}

				// 받은 이미지 클릭시 이벤트
				holder.imageRcvContent.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						if (imageResendable) {
							new AlertDialog.Builder(mContext)
							.setMessage(R.string.attachment_retransfer)
							.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									dialog.dismiss();
								}
							})
							.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									try {
										FileDownloadTask task = new FileDownloadTask(mContext, mHandler,
												GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb),
												clientMsgUuid,
												fileTranInfo, null);
										task.execute();
									} catch (SecurityException e) {
										MTalkLogWriter.e(e);
									}
									dialog.dismiss();
								}
							})
							.create()
							.show();
						} else {
							// 이미지 보여주기
							Intent intent = new Intent();
							intent.setAction(android.content.Intent.ACTION_VIEW);
							intent.setDataAndType(Uri.fromFile(new File(fileTranInfo.getFileUri())), "image/*");
							mActivity.startActivity(intent);
						}
					}
				});
			} catch (InvalidProtocolBufferMicroException e1) {
				MTalkLogWriter.e(e1);
			}
		}
	}

	protected void bindViewReceivedAudio(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		final long clientViewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_MSB));
		final long clientViewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_LSB));
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long clientMsgUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_MSB));
		final long clientMsgUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_LSB));
		final long messageUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_MSB));
		final long messageUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final UUID clientMsgUuid = GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb);
		final int fileTransferInfo = cursor.getColumnIndexOrThrow(MessageTable.KEY_FILE_TRANSFER_INFO);
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		holder.textRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		});
		holder.lLayoutRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		});
		byte[] transeferInfoBytes = cursor.getBlob(fileTransferInfo);
		if (transeferInfoBytes == null) {
			// Not implemented. not in this version.
		} else {
			try {
				final FileTransferInfo fileTranInfo = FileTransferInfo.parseFrom(transeferInfoBytes);
				boolean resendable = false;
				if(fileTranInfo != null
						&& fileTranInfo.hasWorking() 
						&& fileTranInfo.hasNumOfSlice()
						&& fileTranInfo.hasSliceNo() 
						&& fileTranInfo.hasState()){
					holder.seekbarRcvProgress.setVisibility(View.VISIBLE);

					if(fileTranInfo.getWorking()){
						// 작업중이다.
						if(fileTranInfo.getState() == Database.SENDING_MESSAGE){
							// 작업이 끝났다! 사라져 버려!
							holder.seekbarRcvProgress.setVisibility(View.GONE);
						}else if(fileTranInfo.getSliceNo() < 0 || fileTranInfo.getNumOfSlice() <= 0){
							// 시작도 안했다.
							holder.seekbarRcvProgress.setVisibility(View.GONE);	
						}else if(fileTranInfo.getState() == Database.SENDING_SLICE){
							// 작업 진행중!! 진행 상황을 보고 하자!
							holder.seekbarRcvProgress.setVisibility(View.VISIBLE);
							// WEIGHT dip 갯수만큼 쪼개자.( (((진행갯수(ZeroBase))+1)/총갯수) * dip 갯수)
							int progress = ((fileTranInfo.getSliceNo()+1)*100)/(fileTranInfo.getNumOfSlice());
							holder.seekbarRcvProgress.setProgress(progress);
						}else{
							holder.seekbarRcvProgress.setVisibility(View.GONE);	
						}
					}else if(fileTranInfo.hasState()){
						if(fileTranInfo.getSliceNo() < 0 || fileTranInfo.getNumOfSlice() <= 0){
							// 시작도 안했다.
							holder.seekbarRcvProgress.setVisibility(View.GONE);	
						}else if(fileTranInfo.getState() != Database.SENDING_MESSAGE){
							// 다시 전송해야 된다. 알려줘야 됨.
							holder.seekbarRcvProgress.setVisibility(View.VISIBLE);
							holder.seekbarRcvProgress.setSecondaryProgress(holder.seekbarRcvProgress.getMax());
							int progress = ((fileTranInfo.getSliceNo()+1)*100)/(fileTranInfo.getNumOfSlice());
							holder.seekbarRcvProgress.setProgress(progress);
							resendable = true;
						} else {
							// 이미 끝나 있는 작업
							holder.seekbarRcvProgress.setVisibility(View.GONE);
						}
					}
				}else{
					holder.seekbarRcvProgress.setVisibility(View.GONE);
				}
				holder.textRcvContent.setText(R.string.attachment_audio_name);
				if(thumbnailImg != null){
					holder.imageRcvContent.setImageBitmap(thumbnailImg);
				}else{
					holder.imageRcvContent.setImageResource(R.drawable.test_voice);
				}
				// 받은 오디오 클릭시 이벤트
				holder.imageRcvContent.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						GpbSupport.makeUuid(messageUuidMsb, messageUuidLsb);
					}
				});
			} catch (InvalidProtocolBufferMicroException e1) {
				MTalkLogWriter.e(e1);
			}
		}
	}

	protected void bindViewReceivedVideo(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		final long clientViewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_MSB));
		final long clientViewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_VIEW_UUID_LSB));
		final long viewUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_MSB));
		final long viewUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_VIEW_UUID_LSB));
		final long clientMsgUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_MSB));
		final long clientMsgUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_CLIENT_MESSAGE_UUID_LSB));
		final long messageUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_MSB));
		final long messageUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_UUID_LSB));
		final long messageNotiUuidMsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_MSB));
		final long messageNotiUuidLsb = cursor.getLong(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_NOTI_UUID_LSB));
		final UUID clientMsgUuid = GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb);
		final int fileTransferInfo = cursor.getColumnIndexOrThrow(MessageTable.KEY_FILE_TRANSFER_INFO);
		final int status = cursor.getInt(cursor.getColumnIndexOrThrow(MessageTable.KEY_MESSAGE_STATUS));

		holder.textRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		});
		holder.lLayoutRcvContent.setOnLongClickListener(new OnLongClickListener() {
			@Override
			public boolean onLongClick(View v) {
				return onTextLongClick(v, GpbSupport.makeUuidMsg(viewUuidMsb, viewUuidLsb), 
						GpbSupport.makeUuidMsg(messageNotiUuidMsb, messageNotiUuidLsb),
						status, clientMsgUuid);
			}
		});
		byte[] transeferInfoBytes = cursor.getBlob(fileTransferInfo);
		if (transeferInfoBytes == null) {
			// 아직 키만 가지고 있음. 누르면 다운로드.
			holder.textRcvContent.setText(R.string.attachment_video_name);
			if(thumbnailImg != null){
				holder.imageRcvContent.setImageBitmap(thumbnailImg);
			}else {
				holder.imageRcvContent.setImageResource(R.drawable.test_camera);
			}
			holder.imageRcvContent.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					//GpbSupport.makeUuid(messageUuidMsb, messageUuidLsb);
					new AlertDialog.Builder(mContext)
					.setMessage(R.string.attachment_download)
					.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							dialog.dismiss();
						}
					})
					.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							try {
								FileDownloadTask task = new FileDownloadTask(mContext, mHandler,
										GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb),
										GpbSupport.makeUuid(clientMsgUuidMsb, clientMsgUuidLsb),
										um.getAttachFile(), null);
								task.execute();
							} catch (SecurityException e) {
								MTalkLogWriter.e(e);
							}
							dialog.dismiss();
						}
					})
					.create()
					.show();
				}
			});
		} else {
			try {
				final FileTransferInfo fileTranInfo = FileTransferInfo.parseFrom(transeferInfoBytes);
				boolean resendable = false;
				if(fileTranInfo != null 
						&& fileTranInfo.hasWorking() 
						&& fileTranInfo.hasNumOfSlice()
						&& fileTranInfo.hasSliceNo() 
						&& fileTranInfo.hasState()){
					holder.seekbarRcvProgress.setVisibility(View.VISIBLE);

					if(fileTranInfo.getWorking()){
						// 작업중이다.
						if(fileTranInfo.getState() == Database.SENDING_MESSAGE){
							// 작업이 끝났다! 사라져 버려!
							holder.seekbarRcvProgress.setVisibility(View.GONE);
						}else if(fileTranInfo.getSliceNo() < 0 || fileTranInfo.getNumOfSlice() <= 0){
							// 시작도 안했다.
							holder.seekbarRcvProgress.setVisibility(View.GONE);	
						}else if(fileTranInfo.getState() == Database.SENDING_SLICE){
							// 작업 진행중!! 진행 상황을 보고 하자!
							holder.seekbarRcvProgress.setVisibility(View.VISIBLE);
							// WEIGHT dip 갯수만큼 쪼개자.( (((진행갯수(ZeroBase))+1)/총갯수) * dip 갯수)
							int progress = ((fileTranInfo.getSliceNo()+1)*100)/(fileTranInfo.getNumOfSlice());
							holder.seekbarRcvProgress.setProgress(progress);
						}else{
							holder.seekbarRcvProgress.setVisibility(View.GONE);	
						}
					}else if(fileTranInfo.hasState()){
						if(fileTranInfo.getSliceNo() < 0 || fileTranInfo.getNumOfSlice() <= 0){
							// 시작도 안했다.
							holder.seekbarRcvProgress.setVisibility(View.GONE);	
						}else if(fileTranInfo.getState() != Database.SENDING_MESSAGE){
							// 다시 전송해야 된다. 알려줘야 됨.
							holder.seekbarRcvProgress.setVisibility(View.VISIBLE);
							holder.seekbarRcvProgress.setSecondaryProgress(holder.seekbarRcvProgress.getMax());
							int progress = ((fileTranInfo.getSliceNo()+1)*100)/(fileTranInfo.getNumOfSlice());
							holder.seekbarRcvProgress.setProgress(progress);
							resendable = true;
						} else {
							// 이미 끝나 있는 작업
							holder.seekbarRcvProgress.setVisibility(View.GONE);
						}
					}
				}else{
					holder.seekbarRcvProgress.setVisibility(View.GONE);
				}
				holder.textRcvContent.setText(R.string.attachment_video_name);
				final boolean videoResendable = resendable;
				if(thumbnailImg != null){
					holder.imageRcvContent.setImageBitmap(thumbnailImg);
				}else if (! videoResendable) {	//###
					try {
						Bitmap thumbnail = GraphicUtil.getVideoFrame(fileTranInfo.getFileUri());
						if (thumbnail == null) {
							holder.imageRcvContent.setImageResource(R.drawable.test_camera);
						} else {
							holder.imageRcvContent.setImageBitmap(ImageManager.getResizedBitmap(thumbnail,
									(int) Dip.toPixel(THUMB_MAX_SIZE_DIP)));
						}
					} catch (Exception e) {
						MTalkLogWriter.e(e);
						holder.imageRcvContent.setImageResource(R.drawable.test_camera);
					}

				}else{
					holder.imageRcvContent.setImageResource(R.drawable.test_camera);
				}
				// 받은 비디오 클릭시 이벤트
				holder.imageRcvContent.setOnClickListener(new OnClickListener() {
					@Override
					public void onClick(View v) {
						if (videoResendable) {
							new AlertDialog.Builder(mContext)
							.setMessage(R.string.attachment_retransfer)
							.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									dialog.dismiss();
								}
							})
							.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
								@Override
								public void onClick(DialogInterface dialog, int which) {
									try {
										FileDownloadTask task = new FileDownloadTask(mContext, mHandler,
												GpbSupport.makeUuid(clientViewUuidMsb, clientViewUuidLsb),
												clientMsgUuid,
												fileTranInfo, null);
										task.execute();
									} catch (SecurityException e) {
										MTalkLogWriter.e(e);
									}
									dialog.dismiss();
								}
							})
							.create()
							.show();
						} else {
							// 비디오 보여주기
							Intent showMovie = new Intent(Intent.ACTION_VIEW);
							showMovie.setDataAndType(Uri.fromFile(new File(fileTranInfo.getFileUri())), "video/*");
							showMovie.putExtra(MediaStore.EXTRA_FINISH_ON_COMPLETION, false);
							mActivity.startActivity(showMovie);
						}
					}
				});
			} catch (InvalidProtocolBufferMicroException e1) {
				MTalkLogWriter.e(e1);
			}
		}
	}

	protected void bindViewReceivedUnknown(Cursor cursor, BalloonHolder holder, final UserMessage um, Bitmap thumbnailImg) {
		holder.textRcvContent.setVisibility(View.VISIBLE);
		holder.textRcvContent.setText(R.string.attachment_unknown);
		holder.imageRcvContent.setVisibility(View.GONE);
	}

	/**
	 * 섬네일 이미지를 지연 로딩하기 위한 함수.
	 * @param targetView
	 * @param clientMsgUuid
	 * @param uri
	 */
	private void loadImageViewLazy(ImageView targetView, UUID clientMsgUuid, String uri) {
		targetView.setTag(clientMsgUuid);
		Handler lazyLoadHandler = new LazyLoadHandler(targetView);
		new AsyncLazyLoader().execute(lazyLoadHandler, uri, clientMsgUuid);
	}

	/**
	 * 지연된 이미지 로딩을 위한 솔루션
	 * @author Arngard
	 */
	class BubbleImageTuple {
		UUID clientMsgUuid = null;
		Bitmap thumbnail = null;
	}

	/**
	 * 지연된 이미지 로딩을 위한 솔루션
	 * @author Arngard
	 */
	class LazyLoadHandler extends Handler {
		ImageView mLazyLoadTarget = null;

		public LazyLoadHandler(ImageView lazyLoadTarget) {
			mLazyLoadTarget = lazyLoadTarget;
		}
		@Override
		public void handleMessage(Message message) {
			synchronized (ChatListCursorAdapter.this) {
				try {
					BubbleImageTuple tuple = (BubbleImageTuple) message.obj;
					if (tuple.clientMsgUuid.equals((UUID) mLazyLoadTarget.getTag())) {
						mLazyLoadTarget.setImageBitmap(tuple.thumbnail);
					} else {
						// 엉뚱한 뷰에 섬네일 업데이트
					}
				} catch (Exception e) {
					MTalkLogWriter.e(e);
				}
			}
		}
	}
	/**
	 * 지연된 이미지 로딩을 위한 솔루션
	 * @author Arngard
	 */
	class AsyncLazyLoader extends AsyncTask<Object, Void, Void> {

		@Override
		protected Void doInBackground(Object... params) {
			synchronized (ChatListCursorAdapter.this) {
				final Handler lazyLoadHandler = (Handler) params[0];
				String uri = (String) params[1];
				UUID clientMsgUuid = (UUID) params[2];

				try {
					File originalImage = new File(uri);
					Bitmap floorThumbnail = ImageManager.getFloorThumbnail(originalImage, (int) Dip.toPixel(THUMB_LOAD_SIZE_DIP));

					BubbleImageTuple tuple = new BubbleImageTuple();
					tuple.clientMsgUuid = clientMsgUuid;
					tuple.thumbnail = ImageManager.getResizedBitmap(floorThumbnail, (int) Dip.toPixel(THUMB_MAX_SIZE_DIP));

					Message message = lazyLoadHandler.obtainMessage(1, tuple);
					lazyLoadHandler.sendMessage(message);
				} catch (Exception e) {
					MTalkLogWriter.e(e);
				}
			}
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			cancel(true);
		}

		@Override
		protected void onCancelled() {
			super.onCancelled();
			try {
				finalize();
			} catch (Throwable e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public void changeCursor(Cursor cursor) {
		super.changeCursor(cursor);
	}

	@Override
	public Cursor swapCursor(Cursor c) {
		return super.swapCursor(c);
	}

	public void changeCursorAndColumns(Cursor c){
		super.changeCursor(c);
	}

	public static interface CursorToStringConverter{
		CharSequence convertToString(Cursor cursor);
	}

	public void setViewResource(int layout){
		mLayout = layout;
	}

	public static final int MENU_COPY = 0;
	public static final int MENU_DELETE = 1;

	public boolean onTextLongClick(View v, final UUIDMsg viewUuid, final UUIDMsg messageNotiUuid, 
			final int status, final UUID clientMsgUuid) {
		CharSequence copyTmp = null;

		if (v instanceof TextView) {
			TextView copyText = (TextView) v;
			copyTmp = copyText.getText();
		} else if(v.getId() == R.id.lLayoutSndContent) {
			TextView copyText = (TextView)v.findViewById(R.id.textSndContent);
			copyTmp = copyText.getText();
		} else if(v.getId() == R.id.imageSndContent) {
			TextView copyText = (TextView)((View) v.getParent()).findViewById(R.id.textSndContent);
			copyTmp = copyText.getText();
		} else if(v.getId() == R.id.lLayoutRcvContent) {
			TextView copyText = (TextView)v.findViewById(R.id.textRcvContent);
			copyTmp = copyText.getText();
		} else if(v.getId() == R.id.imageRcvContent) {
			TextView copyText = (TextView)((View) v.getParent()).findViewById(R.id.textRcvContent);
			copyTmp = copyText.getText();
		} else {
			copyTmp = null;	// cannot find copy target string.
		}

		final CharSequence copyTarget = copyTmp;
		if (copyTarget == null) {
			new AlertDialog.Builder(mContext).setItems(R.array.ballon_longclick_image, new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					switch (which) {
					case MENU_COPY:
					case MENU_DELETE:
						RemoveMessagesReq removeMessagesReq = new RemoveMessagesReq();
						removeMessagesReq.setViewUuid(viewUuid);
						removeMessagesReq.addNotiUuid(messageNotiUuid);
						RemoveMessagesTask task = new RemoveMessagesTask(mContext, mHandler, removeMessagesReq);
						task.execute();
						break;
					default:
						break;
					}				
				}
			}).show();
			return true;
		} else {
			new AlertDialog.Builder(mContext).setItems(R.array.ballon_longclick, new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					switch (which) {
					case MENU_COPY:
						ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
						clipboard.setText(copyTarget);
						Toast.makeText(mContext , clipboard.getText()+"\n"+ mContext.getString(R.string.toast_copy_clipbaord), Toast.LENGTH_SHORT).show();
						break;
					case MENU_DELETE:
						RemoveMessagesReq removeMessagesReq = new RemoveMessagesReq();
						removeMessagesReq.setViewUuid(viewUuid);
						removeMessagesReq.addNotiUuid(messageNotiUuid);
						RemoveMessagesTask task = new RemoveMessagesTask(mContext, mHandler, removeMessagesReq);
						task.execute();
						break;
					default:
						break;
					}				
				}
			}).show();
			return true;
		}
	}

	/**
	 * 액션 바를 띄워줌
	 * @param context
	 * @param v
	 * @param buddy_id
	 * @param receiverMsb
	 * @param receiverLsb
	 * @param displayName
	 * @param buddyInfo
	 * @param raw_id
	 * @param favorite
	 */
	private static void setOnQuickAction(Context context, View v, int buddy_id, long receiverMsb, long receiverLsb, String displayName, BuddyInfo buddyInfo, int raw_id, int favorite) {
		try {
			// 액션 바를 띄워준다.
			QuickAction quickAction = new QuickAction(v.findViewById(R.id.imageProfile));
			quickAction.addActionItem(new BuddyActionItem(context, ItemType.ONE_TO_ONE, buddy_id, receiverMsb, receiverLsb, buddyInfo, displayName, raw_id, favorite, quickAction));
			quickAction.addActionItem(new BuddyActionItem(context, ItemType.FAVORITE, buddy_id, receiverMsb, receiverLsb, buddyInfo, displayName, raw_id, favorite, quickAction));
			if(raw_id != -1){
				quickAction.addActionItem(new BuddyActionItem(context, ItemType.CALL, buddy_id, receiverMsb, receiverLsb, buddyInfo, displayName, raw_id, favorite, quickAction));
				quickAction.addActionItem(new BuddyActionItem(context, ItemType.SEND_MESSAGE, buddy_id, receiverMsb, receiverLsb, buddyInfo, displayName, raw_id, favorite, quickAction));
			}
			quickAction.addActionItem(new BuddyActionItem(context, ItemType.PROFILEVIEW, buddy_id, receiverMsb, receiverLsb, buddyInfo, displayName, raw_id, favorite, quickAction));
			//			quickAction.addActionItem(new BuddyActionItem(mContext, ItemType.INVITE, buddy_id, receiverMsb, receiverLsb, buddyInfo, displayName, raw_id, favorite, quickAction));
			quickAction.setAnimStyle(QuickAction.ANIM_AUTO);
			quickAction.setMode(QuickAction.MODE_DIALOG);
			quickAction.show();
		} catch (IllegalArgumentException e) {
			MTalkLogWriter.e(e);
		}
	}

}
